package csm.common.net;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.Hashtable;

import csm.common.StringUtil;
import csm.common.xml.XmlDocument;

/**
*
* @author seungmun
* @since 2006.1.18.
*
*/
public class HttpRequester
{
   private String                    baseURL;
   private Hashtable<String, String> requestParams;
   private int                       connectTimeout = 5 * 1000;
   private int                       readTimeout    = 10 * 1000;



   /**
    * @return
    */
   public String getBaseURL()
   {
       return baseURL;
   }

   /**
    * @param baseServiceUri
    */
   public void setBaseURL(String baseURL)
   {
       this.baseURL = baseURL;
   }

   public int getReadTimeout()
   {
       return readTimeout;
   }

   public void setReadTimeout(int readTimeout)
   {
       this.readTimeout = readTimeout;
   }

   /**
    * 연결 응답대기시간을 가져옵니다.<br>
    * 기본값은 5초입니다.
    * @return 밀리초
    */
   public int getConnectTimeout()
   {
       return connectTimeout;
   }

   /**
    * 소켓연결에 대한 응답대기시간을 지정합니다.<br>
    * 기본값은 5초입니다.<br>
    * 지정된 대기시간을 초과하여도 응답이 없는 경우는 Timeout을 발생시킵니다.
    * @param connectTimeout 밀리초
    */
   public void setConnectTimeout(int connectTimeout)
   {
       this.connectTimeout = connectTimeout;
   }

   /**
    * 파라메터값을 입력합니다. (파라메터명은 대소문자를 구분한다.)
    *
    * @param paramName
    * @param paramValue
    */
   public void appendParameter(String paramName, String paramValue)
   {
       if (requestParams == null)
           requestParams = new Hashtable<String, String>();

       if( paramValue == null )
    	   paramValue = "";
       requestParams.put(paramName, paramValue);
   }

   /**
    * Document로 리턴
    *
    * @return
    * @throws Exception
    */
   public XmlDocument execute() throws Exception
   {
       return new XmlDocument(executeString());
   }

   /**
    * URI로 XmlDocument로 받는다.
    *
    * @param uri
    * @return
    * @throws Exception
    */
   public XmlDocument execute(String uri) throws Exception
   {
       return new XmlDocument(executeString(uri));
   }
   public String executeString(String uri) throws Exception{
	   return executeString( uri, "UTF-8");
   }
   /**
    * FullUrl을 통해서 조회하여 리턴한다.
    *
    * @param uri
    * @return
    * @throws Exception
    */
   public String executeString(String uri, String responseEncoding) throws Exception
   {
       HttpURLConnection cn = null;
       BufferedReader br = null;
       try
       {
           URL url = new URL(uri);
           cn = (HttpURLConnection) url.openConnection();

           cn.setConnectTimeout(connectTimeout);
           cn.setRequestProperty("accept-language","ko");
           cn.setReadTimeout(readTimeout);
           cn.setDoOutput(true);

           br = new BufferedReader(new InputStreamReader(cn.getInputStream(), responseEncoding));

           if (cn.getResponseCode() != 200)
               throw new Exception("호출중 오류가 발생했습니다.(" + cn.getResponseCode() + ")");

           StringBuffer sb = new StringBuffer();
           String s;
           while ((s = br.readLine()) != null)
           {
               sb.append(s).append("\n");
           }
           return sb.toString();
       }
       catch( SocketTimeoutException e){
           System.out.println(uri);
           e.printStackTrace();
           return "";
       }
       finally
       {
           if (br != null)
           {
               try
               {
                   br.close();
               }
               catch (IOException e)
               {
                   e.printStackTrace();
               }
               br = null;
           }

           if (cn != null)
           {
               cn.disconnect();
               cn = null;
           }
       }
   }

   /**
    * 요청용 파라메터쿼리문자열을 가져온다.<br>
    * URLEncodeing을 적용하지 않고 가져온다.
    * @return
    */
	public String getParameterQuery() {
		return getParameterQuery("");
	}
	/**
	 * 요청용 파라메터쿼리문자열을 가져온다.
	 * @param urlEncoding 공백이나 빈문자열인 경우, URLEncoding을 적용하지 않고 가져온다.
	 * @return
	 */
	public String getParameterQuery(String urlEncoding)
	{
		StringBuffer sbParam = new StringBuffer();
		if (requestParams != null)
		{
			Enumeration<String> en = requestParams.keys();

			while (en.hasMoreElements())
			{
				String key = en.nextElement();

				if (sbParam.length() > 0)
					sbParam.append("&");

				try
				{
					if( !StringUtil.isNullOrEmpty(urlEncoding))
						sbParam.append(key).append("=").append(URLEncoder.encode(requestParams.get(key), urlEncoding));
					else
						sbParam.append(key).append("=").append(requestParams.get(key));
				}
				catch (UnsupportedEncodingException e) {

					e.printStackTrace();
				}
			}
		}
		return sbParam.toString();
	}

   /**
    * @return
    * @throws Exception
    */
   public String executeString() throws Exception
   {
       HttpURLConnection cn = null;
       BufferedWriter bw = null;
       BufferedReader br = null;

       try
       {
           StringBuffer sbParam = new StringBuffer();
           if (requestParams != null)
           {
               Enumeration<String> en = requestParams.keys();
               while (en.hasMoreElements())
               {
                   String key = en.nextElement();

                   if (sbParam.length() > 0)
                       sbParam.append("&");

                   //sbParam.append(key).append("=").append(URLEncoder.encode(requestParams.get(key), "UTF-8"));
                   sbParam.append(key).append("=").append(requestParams.get(key));
               }
           }

           URL url = new URL(baseURL);
           cn = (HttpURLConnection) url.openConnection();
           cn.setRequestProperty("accept-language","ko");
           cn.setConnectTimeout(connectTimeout);
           cn.setReadTimeout(readTimeout);
           cn.setDoOutput(true);

           bw = new BufferedWriter(new OutputStreamWriter(cn.getOutputStream()));
           bw.write(sbParam.toString());
           bw.flush();

           br = new BufferedReader(new InputStreamReader(cn.getInputStream(), "UTF-8"));

           if (cn.getResponseCode() != 200)
               throw new Exception("호출중 오류가 발생했습니다.(" + cn.getResponseCode() + ")");

           StringBuffer sb = new StringBuffer();
           String s;
           while ((s = br.readLine()) != null)
           {
               sb.append(s).append("\n");
           }

           return sb.toString();

       }
       finally
       {
           if (bw != null)
           {
               try
               {
                   bw.close();
               }
               catch (IOException e)
               {
                   e.printStackTrace();
               }
               bw = null;
           }

           if (br != null)
           {
               try
               {
                   br.close();
               }
               catch (IOException e)
               {
                   e.printStackTrace();
               }
               br = null;
           }

           if (cn != null)
           {
               cn.disconnect();
               cn = null;
           }
       }
   }
}
